#include "Task.h"

//Creates a new task with pointers to a Date and 2 Time classes.
Task::Task() {
	start = QDateTime();
	end = QDateTime();
}

//Intializes a floating task.
void Task::setTask(int setTaskRef, QString setTitle, QDateTime setStart, QDateTime setEnd,
				   QVector<QString> setTags) {
	taskRef = setTaskRef;
	title = setTitle;
	start = setStart;
	end = setEnd;
	tags = setTags;
	updateTaskType();
	updateTaskStatus();
}

//Sets title.
void Task::setTitle(QString setTitle) {
	title = setTitle;
}

//Sets the start date 
void Task::setStartDate(QDate setStartDate) {
	start.setDate(setStartDate);
	updateTaskType();
	updateTaskStatus();
}

//Sets the end date 
void Task::setEndDate(QDate setEndDate) {
	end.setDate(setEndDate);
	updateTaskType();
	updateTaskStatus();
}

//Sets the start time 
void Task::setStartTime(QTime setStartTime) {
	start.setTime(setStartTime);
	updateTaskType();
	updateTaskStatus();
}

//Sets the end time 
void Task::setEndTime(QTime setEndTime) {
	end.setTime(setEndTime);
	updateTaskType();
	updateTaskStatus();
}

void Task::addTag(QString setTag) {
	tags.push_back(setTag);
}

//Returns task type.
Task::TaskType Task::getTaskType() const {
	return type;
}

//Returns task reference number.
int Task::getTaskRef() const {
	return taskRef;
}

//Returns title.
QString Task::getTitle() const {
	return title;
}

//Returns most relevant date of the task.
//Deadline - returns end date
//Meeting - returns start date
//Event - returns start date
QDate Task::getTaskDate() const {
	if (start.date().isNull()) {
		return end.date();
	}
	
	return start.date();
}

//Returns most relevant time of the task.
//Deadline - returns end time
//Meeting - returns start time
//Event - returns start time
QTime Task::getTaskTime() const {
	if (start.time().isNull()) {
		return end.time();
	}
	
	return start.time();
}

//Returns the start date & time of the task.
QDateTime Task::getStartDateTime() const {
	return start;
}
//Returns the end date & time of the task.
QDateTime Task::getEndDateTime() const {
	return end;
}

//Returns the start date of the task.
QDate Task::getStartDate() const {
	return start.date();
}

//Returns the end date of the task.
QDate Task::getEndDate() const {
	return end.date();
}

//Returns the start time of the task.
QTime Task::getStartTime() const {
	return start.time();
}

//Returns the end time of the task.
QTime Task::getEndTime() const {
	return end.time();
}

//Updates the task status and returns it.
Task::TaskStatus Task::getTaskStatus() {
    updateTaskStatus();
	return taskStatus;
}

QVector<QString> Task::getAllTags() const {
	return tags;
}

//Updates the tasktype based its task parameters.
void Task::updateTaskType() {
	if (start.isNull() && end.isNull()) {
		type = FLOATING;
		return;
	}
	
	if (start.isNull() && !end.isNull()) {
		type = DEADLINE;
		return;
	}
	
	if (!start.isNull() && !end.isNull()) {
		QDate startDate = start.date();
		QDate endDate = end.date();
		if (startDate == endDate) {
			type = MEETING;
			return;
		}
		else {
			type = EVENT;
			return;
		}
	}
}

//Updates the task status according to current time, with guards that 
//prevent unmarking complete tasks and modifying task status of floating
//tasks.
void Task::updateTaskStatus() {
	if (taskStatus == Task::TaskStatus::COMPLETE) {
		return;
	}

	switch(type) {
		case FLOATING: taskStatus = NORMAL;
					   return;
		case DEADLINE: 
		case MEETING:  
		case EVENT:    taskStatus = compareTime();
					   return;
	};
}

//Marks task status as complete.
void Task::markComplete() {
	if (taskStatus != COMPLETE) {
		taskStatus = COMPLETE;
	}
}

void Task::unmarkComplete() {
	if (taskStatus == COMPLETE) {
		taskStatus = NORMAL;
		updateTaskStatus();
	}
}

bool Task::isTag(QString tag) {
	return tags.contains(tag);
}

//Initializes the current time, finds the difference between the
//start time of the task and compares the difference. If the 
//difference falls within a particular range, it sets the task 
//status as a particular value.

//Notes:
//1. Can only be called for deadline, meeting and event tasks.
Task::TaskStatus Task::compareTime() {
	QDateTime currTime = QDateTime::currentDateTime();
	QDateTime taskTime = end;
	
	if (taskTime.daysTo(currTime) < 0) {
		return OVERDUE;
	}

	if (taskTime.daysTo(currTime) == 3) {
		return APPROACH3;
	}

	if (taskTime.daysTo(currTime) == 2) {
		return APPROACH2;
	}

	if (taskTime.daysTo(currTime) == 1) {
		return APPROACH1;
	}

	return NORMAL;
}